#ifndef     __EXEC_APP_H
#define     __EXEC_APP_H

#include <QApplication>
#include <QEvent>

constexpr QEvent::Type EXEC_EVENT = static_cast<QEvent::Type>(QEvent::User + 1);

struct ExecEvent : public QEvent {

    ExecEvent() : QEvent(EXEC_EVENT) {}

    virtual void exec() = 0;
    virtual ~ExecEvent() {}
};

template <typename F>
struct ExecEventImpl : public ExecEvent {

    ExecEventImpl(F&& f) : func(std::move(f)) {}

    void exec() override {
        func();
    }

    F func;
};

class ExecApp : public QApplication {

public:
    ExecApp(int argc, char *argv[]) : QApplication(argc, argv) {
    }

protected:
    bool event(QEvent *event) override {
        if (event->type() != EXEC_EVENT) {
            return QApplication::event(event);
        }
        event->accept();
        static_cast<ExecEvent *>(event)->exec();
        return true;
    }
};

template <typename F>
concept ExecTrait = requires(F f) {
    { (f) };
};

template <ExecTrait F>
inline void run_on_ui(F&& f) {
    QEvent *event = new ExecEventImpl<F>(std::move(f));
    qApp->postEvent(qApp, event);
}

#endif
